package com.zyj.springboot.core.advice;

import com.zyj.springboot.core.UnifyResponse;
import com.zyj.springboot.exception.HttpException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;

import javax.servlet.http.HttpServletRequest;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.util.List;
import java.util.Set;

/**
 * @author : zhouyajun
 * @date : 2020-05-13
 */

@ControllerAdvice
public class GlobalExceptionAdvice {

    private Logger logger = LoggerFactory.getLogger(GlobalExceptionAdvice.class);

    @ExceptionHandler(value = Exception.class)
    public UnifyResponse handleException(HttpServletRequest request, Exception ex) {
        String uri = request.getRequestURI();
        String method = request.getMethod();
        System.out.println(ex);
        return UnifyResponse.builder()
                .code(9999)
                .message("服务器错误")
                .requestUri(method + " " + uri)
                .build();
    }

    @ExceptionHandler(value = HttpException.class)
    public ResponseEntity handleHttpException(HttpServletRequest request, HttpException ex) {
        String requestUri = request.getRequestURI();
        String method = request.getMethod();
        System.out.println(ex.getMessage());


        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);

        HttpStatus status = HttpStatus.resolve(ex.getHttpStatusCode());

        return new ResponseEntity<>(
                UnifyResponse.builder()
                        .code(ex.getCode())
                        .message("服务器错误")
                        .requestUri(method + " " + requestUri)
                        .build(), headers, status
        );
    }

    @ExceptionHandler(value = MethodArgumentNotValidException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ResponseBody
    public UnifyResponse handlerBeanValidationException(HttpServletRequest request,
                                                        MethodArgumentNotValidException ex) {
        String requestUri = request.getRequestURI();
        String method = request.getMethod();

        List<ObjectError> errors = ex.getBindingResult().getAllErrors();
        return UnifyResponse.builder()
                .code(5000)
                .message(formatError(errors))
                .requestUri(method + " " + requestUri)
                .build();
    }

    private String formatError(List<ObjectError> errors) {
        StringBuilder builder = new StringBuilder();
        errors.forEach(error -> builder.append(error.getDefaultMessage()).append(";"));
        return builder.toString();
    }

    @ExceptionHandler(ConstraintViolationException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ResponseBody
    public UnifyResponse handlerConstraintViolationException(HttpServletRequest request, ConstraintViolationException ex){
        String requestUri = request.getRequestURI();
        String method = request.getMethod();

        Set<ConstraintViolation<?>> errors = ex.getConstraintViolations();
        return UnifyResponse.builder()
                .code(6000)
                .message(formatConstraintException(errors))
                .requestUri(method + " " + requestUri)
                .build();
    }

    private String formatConstraintException(Set<ConstraintViolation<?>> constraintViolations){
        StringBuilder builder = new StringBuilder();
        constraintViolations.forEach(constraintViolation -> builder.append(constraintViolation.getMessage()));
        return builder.toString();
    }
}
